<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.0.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/wang-cheng/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/wang-cheng/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/wang-cheng/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/wang-cheng/images/logo.svg" color="#222">

<link rel="stylesheet" href="/wang-cheng/css/main.css">


<link rel="stylesheet" href="/wang-cheng/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"cheng-wang123.gitee.io","root":"/wang-cheng/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="hashCode与equalshashCode介绍hashCode()的作用是获取哈希码，也称为散列码；实际上返回的是一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Objcet.java中，Java中的任何类都包含有hashCode()函数。散列表中存的是键值对(key-value)，它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利">
<meta property="og:type" content="article">
<meta property="og:title" content="面试题(二)">
<meta property="og:url" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%8C/index.html">
<meta property="og:site_name" content="诚の博客">
<meta property="og:description" content="hashCode与equalshashCode介绍hashCode()的作用是获取哈希码，也称为散列码；实际上返回的是一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Objcet.java中，Java中的任何类都包含有hashCode()函数。散列表中存的是键值对(key-value)，它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%8C/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%A8%A1%E5%9E%8B.png">
<meta property="article:published_time" content="2022-03-18T03:18:51.000Z">
<meta property="article:modified_time" content="2022-04-30T13:30:58.102Z">
<meta property="article:author" content="王诚">
<meta property="article:tag" content="面试题">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cheng-wang123.gitee.io/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%8C/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%A8%A1%E5%9E%8B.png">

<link rel="canonical" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%8C/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>面试题(二) | 诚の博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/wang-cheng/atom.xml" title="诚の博客" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/wang-cheng/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">诚の博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">记录学习中的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/wang-cheng/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/wang-cheng/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/wang-cheng/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/wang-cheng/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%8C/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          面试题(二)
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-18 11:18:51" itemprop="dateCreated datePublished" datetime="2022-03-18T11:18:51+08:00">2022-03-18</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-30 21:30:58" itemprop="dateModified" datetime="2022-04-30T21:30:58+08:00">2022-04-30</time>
              </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="hashCode与equals"><a href="#hashCode与equals" class="headerlink" title="hashCode与equals"></a><strong>hashCode与equals</strong></h2><h3 id="hashCode介绍"><a href="#hashCode介绍" class="headerlink" title="hashCode介绍"></a><strong>hashCode介绍</strong></h3><p>hashCode()的作用是获取哈希码，也称为散列码；实际上返回的是一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Objcet.java中，Java中的任何类都包含有hashCode()函数。散列表中存的是键值对(key-value)，它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码！(可以快速找到所需要的对象)</p>
<h3 id="为什么要有hashCode"><a href="#为什么要有hashCode" class="headerlink" title="为什么要有hashCode()"></a><strong>为什么要有hashCode()</strong></h3><p><strong>以“HashSet如何检查重复”为例子来说明什么要有hashCode</strong></p>
<p>对象加入HashSet时，HashSet会先计算对象的hashcode值来判断对象加入的位置，看该位置是否有值，如果没有、HashSet会假设对象没有重复出现。但是如果发现有值，这时会调用equals()方法来检查两个对象是否真的相同。如果两者相同，HashSet就不会让其加入操作成功。如果不同得话，就会重新散列(重新调用散列算法计算出一个散列值，这个散列值肯定会做一些操作比如加盐，否则计算出来的散列值与第一次计算出来的散列值相同，就是做无用功了)到其他位置。这样就大大减少了equals的次数，相应就大大提高了执行速度。</p>
<ul>
<li>如果两个对象相等，则hashcode一定也是相同的</li>
<li>两个对象相等，对两个对象分别调用equals方法都返回true</li>
<li>两个对象有相同的hashcode值，它们也不一定是相等的(所以才会有HashSet在加入对象时，如果发现有值，则会调用equals方法再来判断是否真的相等)</li>
<li>因此，equals方法被覆盖过，则hashcode方法也必须被覆盖</li>
<li>hashcode()的默认行为是对堆上的对象产生独特值。如果没有重写hashcode()，则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)</li>
</ul>
<h2 id="为什么要使用HashMap"><a href="#为什么要使用HashMap" class="headerlink" title="为什么要使用HashMap"></a><strong>为什么要使用HashMap</strong></h2><p>对于要求查询次数特别多，查询效率比较高同时插入和删除的次数比较少的情况下，通常会选择ArrayList，因为它的底层是通过数组实现的。对于插入和删除次数比较多同时在查询次数不多的情况下，通常会选择LinkedList，因为它的底层是通过链表实现的。</p>
<p>但现在同时要求插入，删除，查询效率都很高的情况下我们该如何选择容器呢？<br>那么就有一种新的容器叫HashMap，他里面既有数组结构，也有链表结构，所以可以弥补相互的缺点。而且HashMap主要用法是get()和put() 。</p>
<h2 id="HashMap如何扩容"><a href="#HashMap如何扩容" class="headerlink" title="HashMap如何扩容"></a><strong>HashMap如何扩容</strong></h2><p>HashMap的size大于等于(容量*加载因子)的时候,会触发扩容的操作,这个是个代价不小的操作。</p>
<p>为什么要扩容呢？HashMap默认的容量是16,随着元素不断添加到HashMap里,出现hash冲突的机率就更高,那每个桶对应的链表就会更长,</p>
<p>这样会影响查询的性能,因为每次都需要遍历链表,比较对象是否相等,一直到找到元素为止。</p>
<p>为了提升查询性能,只能扩容,减少hash冲突,让元素的key尽量均匀的分布。</p>
<p>扩容的时候需要重新计算元素的数组下标</p>
<p>1、重新分配一个新的Entry数组</p>
<p>2、重新计算原来元素的在新数组中的下标(比较耗资源)</p>
<p>index = HashCode（key） &amp; (Length - 1) jdk1.8 </p>
<p>扩容时使用位运算，<code>(n-1) &amp; hash</code> 。</p>
<p>因为用乘法会影响CPU的性能，计算机不支持乘法运算，最终都会转化为加法运算。</p>
<h2 id="JDk1-7HashMap扩容死循环问题"><a href="#JDk1-7HashMap扩容死循环问题" class="headerlink" title="JDk1.7HashMap扩容死循环问题"></a><strong>JDk1.7HashMap扩容死循环问题</strong></h2><p>HashMap是一个线程不安全的容器，在最坏的情况下，所有元素都定位到同一个位置，形成一个长长的链表，这样get一个值时，最坏情况需要遍历所有节点，性能变成了O(n)。</p>
<p>JDK1.7中HashMap采用头插法拉链表，所谓头插法，即在每次都在链表头部（即桶中）插入最后添加的数据。</p>
<p>死循环问题只会出现在多线程的情况下。</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">假设在原来的链表中，<span class="selector-tag">A</span>节点指向了<span class="selector-tag">B</span>节点。</span><br><span class="line">在线程<span class="number">1</span>进行扩容时，由于使用了头插法，链表中<span class="selector-tag">B</span>节点指向了<span class="selector-tag">A</span>节点。</span><br><span class="line">在线程<span class="number">2</span>进行扩容时，由于使用了头插法，链表中<span class="selector-tag">A</span>节点又指向了<span class="selector-tag">B</span>节点。</span><br><span class="line">在线程n进行扩容时，…</span><br><span class="line">这就容易出现问题了。。在并发扩容结束后，可能导致<span class="selector-tag">A</span>节点指向了<span class="selector-tag">B</span>节点，<span class="selector-tag">B</span>节点指向了<span class="selector-tag">A</span>节点，链表中便有了环！！！</span><br></pre></td></tr></table></figure>
<h2 id="HashMap和HashTable的区别、底层实现是什么"><a href="#HashMap和HashTable的区别、底层实现是什么" class="headerlink" title="HashMap和HashTable的区别、底层实现是什么"></a><strong>HashMap和HashTable的区别、底层实现是什么</strong></h2><p>1、区别:</p>
<ul>
<li><p>HashMap方法没有synchronized修饰，线程非安全，HashTable线程安全(HashTable的添加、删除等方法都有synchronized修饰)</p>
</li>
<li><p>HashMap允许key和value为null，而HashTable不允许</p>
</li>
</ul>
<p>2、底层实现：数组+链表</p>
<p>jdk8开始链表高度到8、数组长度超过64，链表转变为红黑树，元素以内部类Node节点存在</p>
<ul>
<li><p>计算key的hash值，二次hash(再次计算hash值)然后对数组长度取模，对应到数组下标</p>
</li>
<li><p>如果没有产生hash冲突(下标位置没有元素)，则直接创建Node存入数组</p>
</li>
<li><p>如果产生hash冲突，先进行equals比较，相同则取代该元素，不同，则判断链表高度插入链表，链表高度达到8，并且数组长度到64则转变为红黑树，长度低于6则将红黑树转回链表</p>
</li>
<li><p>key为null，存到下标为0的位置</p>
</li>
</ul>
<h2 id="HashMap扩容为什么总是2的次幂？"><a href="#HashMap扩容为什么总是2的次幂？" class="headerlink" title="HashMap扩容为什么总是2的次幂？"></a><strong>HashMap扩容为什么总是2的次幂？</strong></h2><p>HashMap扩容主要是给数组扩容的，因为数组长度不可变，而链表是可变长度的。从HashMap的源码中可以看到HashMap在扩容时选择了位运算，向集合中添加元素时，会使用(n - 1) &amp; hash的计算方法来得出该元素在集合中的位置。只有当对应位置的数据都为1时，运算结果也为1，当HashMap的容量是2的n次幂时，(n-1)的2进制也就是1111111<em>*</em>111这样形式的，这样与添加元素的hash值进行位运算时，能够充分的散列，使得添加的元素均匀分布在HashMap的每个位置上，减少hash碰撞。</p>
<p>另外，HashMap的初始容量是2的n次幂，扩容也是2倍的形式进行扩容，是因为容量是2的n次幂，可以使得添加的元素均匀分布在HashMap中的数组上，减少hash碰撞，避免形成链表的结构，使得查询效率降低！</p>
<p>index = HashCode（key） &amp; (Length - 1) jdk1.8</p>
<h2 id="HashMap负载因子为什么是0-75"><a href="#HashMap负载因子为什么是0-75" class="headerlink" title="HashMap负载因子为什么是0.75"></a><strong>HashMap负载因子为什么是0.75</strong></h2><p>通俗来讲，当负载因子为1.0时，意味着只有当hashMap装满之后才会进行扩容，虽然空间利用率有大的提升，但是这就会导致大量的hash冲突，使得查询效率变低。</p>
<h2 id="为什么非要使用红黑树呢？"><a href="#为什么非要使用红黑树呢？" class="headerlink" title="为什么非要使用红黑树呢？"></a><strong>为什么非要使用红黑树呢？</strong></h2><p>这个选择是综合各种考虑之下的，既要put效率很高，同时也要get效率很高，红黑树就是其中一种。</p>
<h2 id="红黑树的特性"><a href="#红黑树的特性" class="headerlink" title="红黑树的特性"></a><strong>红黑树的特性</strong></h2><ol>
<li><p>节点是红色或黑色；</p>
</li>
<li><p>根节点是黑色；</p>
</li>
<li><p>每个叶子节点都是黑色的空节点（NIL节点）；</p>
</li>
</ol>
<p>4  每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)；</p>
<ol>
<li><p>从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点；</p>
</li>
<li><p>每次新插入的节点都必须是红色。</p>
</li>
</ol>
<p>红黑树从根节点到叶子节点的最长路径不会超过最短路径的两倍</p>
<p>由于父节点27是红色节点，因此这种情况打破了红黑树的规则4（每个红色节点的两个子节点都是黑色），必须进行调整，使之重新符合红黑树的规则。</p>
<p>常用的调整方法有三种：</p>
<ol>
<li><p>左旋转</p>
</li>
<li><p>右旋转</p>
</li>
<li><p>变色</p>
</li>
</ol>
<p>红黑树的应用：</p>
<ol>
<li><p>TreeSet</p>
</li>
<li><p>TreeMap</p>
</li>
<li><p>HashMap（JDK8）</p>
</li>
</ol>
<h2 id="ConcurrentHashMap的实现原理"><a href="#ConcurrentHashMap的实现原理" class="headerlink" title="ConcurrentHashMap的实现原理"></a><strong>ConcurrentHashMap的实现原理</strong></h2><p>线程安全的实现机制：</p>
<ol>
<li><p>初始化数组或头节点时，ConcurrentHashMap并没有加锁，而是CAS的方式进行原子替换（原子操作，基于Unsafe类的原子操作API）。</p>
</li>
<li><p>插入数据时会进行加锁处理，但锁定的不是整个数组，而是槽中的头节点。所以，ConcurrentHashMap中锁的粒度是槽，而不是整个数组，并发的性能很好。</p>
</li>
<li><p>扩容时会进行加锁处理，锁定的仍然是头节点。并且，支持多个线程同时对数组扩容，提高并发能力。每个线程需先以CAS操作抢任务，争抢一段连续槽位的数据转移权。抢到任务后，该线程会锁定槽内的头节点，然后将链表或树中的数据迁移到新的数组里。</p>
</li>
<li><p>查找数据时并不会加锁，所以性能很好。另外，在扩容的过程中，依然可以支持查找操作。如果某个槽还未进行迁移，则直接可以从旧数组里找到数据。如果某个槽已经迁移完毕，但是整个扩容还没结束，则扩容线程会创建一个转发节点存入旧数组，届时查找线程根据转发节点的提示，从新数组中找到目标数据。</p>
</li>
</ol>
<p>加分回答：<br><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ConcurrentHashMap实现线程安全的难点在于多线程并发扩容，即当一个线程在插入数据时，若发现数组正在扩容，那么它就会立即参与扩容操作，完成扩容后再插入数据到新数组。在扩容的时候，多个线程共同分担数据迁移任务，每个线程负责的迁移数量是 (数组长度 &gt;&gt;&gt; <span class="number">3</span>) / <span class="meta">CPU</span>核心数。</span><br><span class="line"></span><br><span class="line">也就是说，为线程分配的迁移任务，是充分考虑了硬件的处理能力的。多个线程依据硬件的处理能力，平均分摊一部分槽的迁移工作。另外，如果计算出来的迁移数量小于<span class="number">16</span>，则强制将其改为<span class="number">16</span>，这是考虑到目前服务器领域主流的<span class="meta">CPU</span>运行速度，每次处理的任务过少，对于<span class="meta">CPU</span>的算力也是一种浪费。</span><br></pre></td></tr></table></figure></p>
<h2 id="ConcurrentHashMap的扩容机制"><a href="#ConcurrentHashMap的扩容机制" class="headerlink" title="ConcurrentHashMap的扩容机制"></a><strong>ConcurrentHashMap的扩容机制</strong></h2><p>1.7版本</p>
<ol>
<li><p>1.7版本的ConcurrentHashMap是基于Segment分段实现的</p>
</li>
<li><p>每个Segment相对于一个小型的HashMap</p>
</li>
<li><p>每个Segment内部会进行扩容，和HashMap的扩容逻辑类似</p>
</li>
<li><p>先生成新的数组，然后转移元素到新数组种</p>
</li>
<li><p>扩容的判断也是每个Segment内部独立判断，判断是否超过阈值</p>
</li>
</ol>
<p>1.8版本</p>
<ol>
<li><p>1.8版本的ConcurrentHashMap不再基于Segment实现</p>
</li>
<li><p>当某个线程进行put时，如果发现ConcurrentHashMap正在进行扩容那么该线程一起扩容</p>
</li>
<li><p>如果某个线程put时，发现没有正在进行扩容，则将key-value添加到ConcurrentHashMap中，然后判断是否超过阈值，超过了则进行扩容</p>
</li>
<li><p>ConcurrentHashMap是支持多个线程同时扩容的</p>
</li>
<li><p>扩容之前也先生成一个新的数组</p>
</li>
<li><p>在转移元素时，先将原数组分组，将每组分给不同的线程来进行元素的转移，每个线程负责一组或多组的元素转移工作</p>
</li>
</ol>
<h2 id="ConcurrentHashMap原理，在jdk7和jdk8版本的区别"><a href="#ConcurrentHashMap原理，在jdk7和jdk8版本的区别" class="headerlink" title="ConcurrentHashMap原理，在jdk7和jdk8版本的区别"></a><strong>ConcurrentHashMap原理，在jdk7和jdk8版本的区别</strong></h2><p>jdk7:<br>数据结构：ReentrantLock+Segment+HashEntry,一个Segment中包含一个HashEntry数组，每个HashEntry又是一个链表结构(这个结构保证的线程安全)。</p>
<p>锁：Segment分段锁 Segment继承了ReentrantLock,锁定操作的Segment，其他的Segment不受影响，并发度为segment个数，可以通过构造函数指定，数组扩容不会影响其他的segment。</p>
<p>元素查询：二次hash，第一次Hash定位到Segment，第二次Hash定位到元素所在的链表的头部(数组下标)</p>
<p>get方法无需加锁，volatile保证</p>
<p>jdk8:<br>数据结构：synchronized+CAS(乐观锁)+数组(Node) + 链表(当链表长度大于8时，链表结构转为红黑二叉树)结构，Node的val和next都用volatile修饰，保证可见性。</p>
<p>查找，替换，赋值操作都是用CAS</p>
<p>扩容、Hash冲突的时候CAS不能保证安全，所以使用synchronized</p>
<p>锁：锁链表(Node)的head节点，不像jdk7锁的是一个segment，所以不影响其他元素的读写，锁粒度更细，效率更高，扩容时，阻塞所有的读写操作、并发扩容</p>
<p>读操作无锁：</p>
<ul>
<li>Node的val和next使用volatile修饰，读写线程对该变量互相可见</li>
<li>数组用volatile修饰，保证扩容时被读线程感知</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://baijiahao.baidu.com/s?id=1724634306266520505&amp;wfr=spider&amp;for=pc">https://baijiahao.baidu.com/s?id=1724634306266520505&amp;wfr=spider&amp;for=pc</a></p>
<h2 id="ArrayList和LinkedList的区别"><a href="#ArrayList和LinkedList的区别" class="headerlink" title="ArrayList和LinkedList的区别"></a><strong>ArrayList和LinkedList的区别</strong></h2><p>ArrayList:基于<strong>动态数组</strong>，连续内存存储(数组特性),适合下标访问(随机访问)。扩容机制：因为数组长度固定，超出长度存数据时需要新建数组，然后将老数组的数据拷贝到新数组，如果不是尾部插入数据还会涉及到元素的移动(往后复制一份，插入新元素)，使用尾插法并指定初始容量可以极大提高性能、甚至超过LinkedList(需要创建大量Node对象)。</p>
<p>LinkedList:基于链表，可以存储在分散的内存中，适合做数据插入和删除操作，不适合查询:需要逐一遍历，<strong>遍历LinkedList必须使用iterator不能使用for循环，因为每次for循环体内通过get(i)取得某一元素时都需要对list重新进行遍历，性能消耗极大。</strong>另外不要试图使用indexOf等返回元素索引，并利用其进行遍历，使用indexOf对list进行遍历，当结果为空时会遍历整个列表。</p>
<h2 id="集合框架中的线程安全类你知道哪些"><a href="#集合框架中的线程安全类你知道哪些" class="headerlink" title="集合框架中的线程安全类你知道哪些"></a><strong>集合框架中的线程安全类你知道哪些</strong></h2><p>Vector、Stack、Hashtable、java.util.concurrent包下所有的集合类都是线程安全的</p>
<h3 id="如何实现一个IOC容器"><a href="#如何实现一个IOC容器" class="headerlink" title="如何实现一个IOC容器"></a><strong>如何实现一个IOC容器</strong></h3><ol>
<li><p>配置文件配置包扫描路径</p>
</li>
<li><p>递归包扫描获取.class文件</p>
</li>
<li><p>反射、确定需要交给IOC管理的类</p>
</li>
<li><p>对需要注入的类进行依赖注入</p>
</li>
</ol>
<ul>
<li>配置文件中指定需要扫描的包路径</li>
<li>定义一些注解，分别表示访问控制层、业务服务层、数据持久层、依赖注入层、获取配置文件注解。</li>
<li>从配置文件中获取需要扫描的包路径，获取到当前路径下的文件信息及文件夹信息，我们将当前路径下所有以.class结尾的文件添加到一个Set集合中进行存储</li>
<li>遍历这个Set集合，获取在类上有指定注解的类，并将其交给IOC容器，定义一个安全的Map用来存储这些对象。</li>
<li>遍历这个IOC容器，获取到每一个类的实例，判断里面是否有依赖其他的类的实例，然后进行依赖注入。</li>
</ul>
<h3 id="什么是字节码？采用字节码的好处是什么"><a href="#什么是字节码？采用字节码的好处是什么" class="headerlink" title="什么是字节码？采用字节码的好处是什么"></a><strong>什么是字节码？采用字节码的好处是什么</strong></h3><p>java中的编译器和解释器:</p>
<p>Java中引入了虚拟机的概念，即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个共同的接口</p>
<p>编译程序只需要面向虚拟机，生成虚拟机能够理解的代码，然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中，这种供虚拟机理解的代码叫做字节码(即扩展名为.class的文件)，它不面向任何特定的处理器，只面向虚拟机。</p>
<p>每一种平台的解释器是不同的，但是实现的虚拟机是相同的。Java源程序经过编译器编译后生成字节码，字节码由虚拟机解释执行，虚拟机将每一条要执行的字节码送给解释器，解释器将其翻译成特定机器上的机器码，然后在特定的机器上运行。这也就解释了Java的编译与解释并存的特点。</p>
<p>Java源代码—-&gt;编译器—-&gt;jvm可执行的Java字节码(即虚拟指令)—-&gt;jvm——&gt;jvm中的解释器——&gt;机器可执行的二进制机器码——&gt;程序运行</p>
<p><strong>采用字节码的好处:</strong></p>
<p>Java语言通过字节码的方式，在一定程度上解决了传统解释型语言执行效率低的问题(传统解释型语言是解释一句执行一句，而Java是先把代码编译好，再一起解释，这样效率高)，同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效，而且，由于字节码并不专对一种特定的机器，因此，Java程序无须重新编译便可在多种不同的计算机上运行。</p>
<h3 id="什么是面向对象？谈一谈你对面向对象的理解"><a href="#什么是面向对象？谈一谈你对面向对象的理解" class="headerlink" title="什么是面向对象？谈一谈你对面向对象的理解"></a><strong>什么是面向对象？谈一谈你对面向对象的理解</strong></h3><p>什么是面向对象？</p>
<p>对比面向过程，是两种不同的处理问题的角度</p>
<p>面向过程更注重事情的每一个步骤及顺序，面向对象更注重事情有哪些参与者(对象)及各自需要做什么</p>
<p>比如：洗衣机洗衣服</p>
<p>面向过程会将任何拆解成一系列的步骤(函数)。1、打开洗衣机———&gt;2、放衣服————&gt;3、放洗衣粉————&gt;4、清洗—————&gt;5、烘干</p>
<p>面向对象会拆出人和洗衣机两个对象：</p>
<p>人：打开洗衣机  放衣服  放洗衣粉</p>
<p>洗衣机：清洗  烘干</p>
<p>从以上例子看出，面向过程比较直接高效，而面向对象更易于复用、扩展和维护</p>
<p>面向对象</p>
<p><strong>封装</strong>：封装的意义，在于明确标识出允许外部使用的所有成员函数和数据项</p>
<p>内部细节对外部调用透明，外部调用无须修改或者关心内部实现</p>
<p>1、javabean的属性私有，提供getset对外访问，因为属性的赋值或者获取逻辑只能由javabean本身决定。而不能由外部胡乱修改。<br><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="title class_">String</span> name;</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">void</span> <span class="title function_">setName</span>(<span class="params"><span class="built_in">String</span> name</span>)&#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&quot;tuling_&quot;</span> + name;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//该name有自己的命名规则，明显不能由外部直接赋值</span></span><br></pre></td></tr></table></figure></p>
<p>2、orm框架</p>
<p>操作数据库，我们不需要关心链接是怎么建立的、sql是如何执行的，只需要引入mybatis调用方法访问即可</p>
<p><strong>继承</strong>：继承基类的方法，并做出自己的改变和/扩展</p>
<p>子类共性的方法或者属性直接使用父类的，而不需要自己再定义，只需扩展自己个性化的</p>
<p><strong>多态</strong>：基于对象所属类的不同，外部对同一个方法的调用，实际执行的逻辑不同</p>
<p>多态三个条件：继承，方法重写，父类引用指向子类对象<br><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">父类类型 变量名 <span class="operator">=</span> new 子类对象<span class="comment">;</span></span><br><span class="line">变量名.方法名()<span class="comment">;</span></span><br></pre></td></tr></table></figure><br>多态弊端:无法调用子类特有的功能</p>
<h3 id="双亲委派模型"><a href="#双亲委派模型" class="headerlink" title="双亲委派模型"></a><strong>双亲委派模型</strong></h3><img src="/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%BA%8C/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%A8%A1%E5%9E%8B.png" class title="双亲委派模型">
<p>双亲委派模型的好处:</p>
<ul>
<li><p>主要为了安全性，避免用户自己编写的类动态替换Java的一些核心类，比如String</p>
</li>
<li><p>同时也避免了类的重复加载，因为JVM中区分不同类，不仅仅是根据类名(全路径)，相同的class文件被不同的ClassLoader加载就是不同的两个类</p>
</li>
</ul>
<h3 id="java中的异常体系"><a href="#java中的异常体系" class="headerlink" title="java中的异常体系"></a><strong>java中的异常体系</strong></h3><p>Java中的所有异常都来自顶级父类Throwable</p>
<p>Throwable下有两个子类Exception和Erro</p>
<p>Error是程序无法处理的错误，一旦出现这个错误，则程序被迫停止运行</p>
<p>Exception不会导致程序停止，又分为两个部分RunTimeException运行时异常和CheckedException检查异常(例如int类型变量被赋值String)</p>
<p>RunTimeException常常发生在程序运行过程中，会导致程序当前线程执行失败。CheckedException常常发生在程序编译过程中，会导致程序编译不通过</p>

    </div>

    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/wang-cheng/tags/%E9%9D%A2%E8%AF%95%E9%A2%98/" rel="tag"># 面试题</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/wang-cheng/2022/03/18/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%B8%80/" rel="prev" title="面试题(一)">
      <i class="fa fa-chevron-left"></i> 面试题(一)
    </a></div>
      <div class="post-nav-item">
    <a href="/wang-cheng/2022/03/19/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%B8%89/" rel="next" title="面试题(三)">
      面试题(三) <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#hashCode%E4%B8%8Eequals"><span class="nav-number">1.</span> <span class="nav-text">hashCode与equals</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#hashCode%E4%BB%8B%E7%BB%8D"><span class="nav-number">1.1.</span> <span class="nav-text">hashCode介绍</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%9C%89hashCode"><span class="nav-number">1.2.</span> <span class="nav-text">为什么要有hashCode()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8HashMap"><span class="nav-number">2.</span> <span class="nav-text">为什么要使用HashMap</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#HashMap%E5%A6%82%E4%BD%95%E6%89%A9%E5%AE%B9"><span class="nav-number">3.</span> <span class="nav-text">HashMap如何扩容</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JDk1-7HashMap%E6%89%A9%E5%AE%B9%E6%AD%BB%E5%BE%AA%E7%8E%AF%E9%97%AE%E9%A2%98"><span class="nav-number">4.</span> <span class="nav-text">JDk1.7HashMap扩容死循环问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#HashMap%E5%92%8CHashTable%E7%9A%84%E5%8C%BA%E5%88%AB%E3%80%81%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0%E6%98%AF%E4%BB%80%E4%B9%88"><span class="nav-number">5.</span> <span class="nav-text">HashMap和HashTable的区别、底层实现是什么</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#HashMap%E6%89%A9%E5%AE%B9%E4%B8%BA%E4%BB%80%E4%B9%88%E6%80%BB%E6%98%AF2%E7%9A%84%E6%AC%A1%E5%B9%82%EF%BC%9F"><span class="nav-number">6.</span> <span class="nav-text">HashMap扩容为什么总是2的次幂？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#HashMap%E8%B4%9F%E8%BD%BD%E5%9B%A0%E5%AD%90%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF0-75"><span class="nav-number">7.</span> <span class="nav-text">HashMap负载因子为什么是0.75</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9D%9E%E8%A6%81%E4%BD%BF%E7%94%A8%E7%BA%A2%E9%BB%91%E6%A0%91%E5%91%A2%EF%BC%9F"><span class="nav-number">8.</span> <span class="nav-text">为什么非要使用红黑树呢？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BA%A2%E9%BB%91%E6%A0%91%E7%9A%84%E7%89%B9%E6%80%A7"><span class="nav-number">9.</span> <span class="nav-text">红黑树的特性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ConcurrentHashMap%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="nav-number">10.</span> <span class="nav-text">ConcurrentHashMap的实现原理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ConcurrentHashMap%E7%9A%84%E6%89%A9%E5%AE%B9%E6%9C%BA%E5%88%B6"><span class="nav-number">11.</span> <span class="nav-text">ConcurrentHashMap的扩容机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ConcurrentHashMap%E5%8E%9F%E7%90%86%EF%BC%8C%E5%9C%A8jdk7%E5%92%8Cjdk8%E7%89%88%E6%9C%AC%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">12.</span> <span class="nav-text">ConcurrentHashMap原理，在jdk7和jdk8版本的区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ArrayList%E5%92%8CLinkedList%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">13.</span> <span class="nav-text">ArrayList和LinkedList的区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E4%B8%AD%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%B1%BB%E4%BD%A0%E7%9F%A5%E9%81%93%E5%93%AA%E4%BA%9B"><span class="nav-number">14.</span> <span class="nav-text">集合框架中的线程安全类你知道哪些</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAIOC%E5%AE%B9%E5%99%A8"><span class="nav-number">14.1.</span> <span class="nav-text">如何实现一个IOC容器</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E5%AD%97%E8%8A%82%E7%A0%81%EF%BC%9F%E9%87%87%E7%94%A8%E5%AD%97%E8%8A%82%E7%A0%81%E7%9A%84%E5%A5%BD%E5%A4%84%E6%98%AF%E4%BB%80%E4%B9%88"><span class="nav-number">14.2.</span> <span class="nav-text">什么是字节码？采用字节码的好处是什么</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%EF%BC%9F%E8%B0%88%E4%B8%80%E8%B0%88%E4%BD%A0%E5%AF%B9%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%90%86%E8%A7%A3"><span class="nav-number">14.3.</span> <span class="nav-text">什么是面向对象？谈一谈你对面向对象的理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%A8%A1%E5%9E%8B"><span class="nav-number">14.4.</span> <span class="nav-text">双亲委派模型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#java%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8%E4%BD%93%E7%B3%BB"><span class="nav-number">14.5.</span> <span class="nav-text">java中的异常体系</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">王诚</p>
  <div class="site-description" itemprop="description">命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/wang-cheng/archives/">
        
          <span class="site-state-item-count">32</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/wang-cheng/tags/">
          
        <span class="site-state-item-count">12</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">王诚</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/wang-cheng/lib/anime.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.ui.min.js"></script>

<script src="/wang-cheng/js/utils.js"></script>

<script src="/wang-cheng/js/motion.js"></script>


<script src="/wang-cheng/js/schemes/pisces.js"></script>


<script src="/wang-cheng/js/next-boot.js"></script>




  















  

  

  

</body>
</html>
